#pragma once
#include <iostream>
#include "nocopy.hpp"
#include "Log.hpp"
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <cerrno>
#include <cstring>
#include "commd.hpp"
#include "InitAddr.hpp"
using namespace std;


static const int default_port = 6666;
static const int default_sockfd = -1;
static const int default_size = 1024;


class UdpServer : public nocopy {
  public :
  UdpServer(const uint16_t port = default_port) 
    :_socketfd(default_sockfd)
    ,_port(port)
  {

  }

  // 初始化服务器
  void Init() {
    // 创建套接字
    _socketfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (_socketfd < 0) {
      lg.LogMessage(Fatal, "socket err: %d %s", errno, strerror(errno));
      exit(Socket_Err);
    }
    // 创建套接字成功
    lg.LogMessage(Info, "create socket success!, socketfd is %d", _socketfd);

    // 填充套接字结构体
    struct sockaddr_in local;
    bzero(&local, sizeof local);

    local.sin_family = AF_INET; // 协议家族
    local.sin_port = htons(_port); // 将端口号的主机序列转化成网络序列
    // local.sin_addr.s_addr = inet_addr(_ip.c_str()); // 将字符串模式的点分十进制的ip地址转化成16位的整型ip地址
    local.sin_addr.s_addr = INADDR_ANY; // 

    // 将网络信息绑定进内核
    socklen_t len = sizeof local;
    int n = ::bind(_socketfd, (struct sockaddr*)&local, len);
    if (n != 0) {
      lg.LogMessage(Fatal, "bind err %d, %s", errno, strerror(errno));
      exit(Bind_Err);
    }
    lg.LogMessage(Info, "bind success");
  }

  // 启动服务器
  void Start() {
    // 服务器收发消息，一直不退出
    while (true) {
      char buffer[default_size];
      struct sockaddr_in peer;
      socklen_t len = sizeof peer;
      int n = recvfrom(_socketfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr*)&peer, &len);
      if (n > 0) {
        // 提取客户端信息
        InitAddr addr(peer);
        string clientinfo = addr.get_Info();
        buffer[n] = '\0';
        cout << clientinfo << "# "<< buffer << endl;

        // 回发消息
        int res = sendto(_socketfd, buffer, strlen(buffer), 0, (struct sockaddr*)&peer, len);
      }

    }

  }


  ~UdpServer() {
    
  }
  private :
  int _socketfd; // 套接字文件描述符
  uint16_t _port; // 端口号
};
